#pragma once
#include <cstdlib>
#include <cassert>
#include <sys/epoll.h>
#include "Fcntl.hpp"
#include "Funtion.hpp"
using fun_t = std::function<void(int, std::string &, std::unordered_map<int, IO *> &)>;
void Accept(int sock, std::unordered_map<int, IO *> &ptr)
{
    // 找到对应的节点
    auto cur = ptr.find(sock);
    assert(cur != ptr.end());
    // 构建映射关系
    IO *s = new IO;
    s->p = cur->second->p;
    s->ep = cur->second->ep;
    s->esp = cur->second->esp;
    // 正确读取
    while (true)
    {
        int serversock = cur->second->p->Accept();
        if (serversock >= 0)
        {
            s->_sock = serversock;
            // 首先设置非阻塞读取
            setblock(serversock);
            // 插入对应关系
            std::pair<int, IO *> op(serversock, s);
            ptr.emplace(op);
            // 插入epoll模型
            s->ep->EpollCtl(EPOLL_CTL_ADD, serversock, EPOLLET | EPOLLIN);
            std::cout << "insert success sock:" << serversock << std::endl;
        }
        if (serversock < 0)
        {
            if (errno == EWOULDBLOCK || errno == EAGAIN)
            {
                std::cout << "没数据，请再试一次" << std::endl;
                break;
            }
            else if (errno == EINTR)
            {
                std::cout << "被中断，请再试一次" << std::endl;
                continue;
            }
            else
            {
                std::cout << "accept fail:" << strerror(errno) << std::endl;
                break;
            }
        }
    }
}
void Recv(int sock, std::unordered_map<int, IO *> &ptr)
{
    auto cur = ptr.find(sock);
    assert(cur != ptr.end());
    while (true)
    {
        char buffer[1024];
        memset(buffer, 0, 1024);
        ssize_t s = recv(sock, buffer, 1023, 0);
        if (s > 0)
        {
            buffer[s] = '\0';
            cur->second->_inbuffer += buffer;
        }
        if (s == 0)
        {
            std::cout << "客户端退出" << std::endl;
            // 从epoll中删除节点
            cur->second->ep->EpollCtl(EPOLL_CTL_DEL, sock, 0);
            // 删除对应关系
            ptr.erase(sock);
            // 关闭文件描述符
            close(sock);
            break;
        }
        if (s < 0)
        {
            if (errno == EWOULDBLOCK || errno == EAGAIN)
            {
                std::cout << "没数据，请再试一次" << std::endl;
                cur->second->_inbuffer += std::to_string(sock);
                cur->second->_inbuffer += 'Y';
                fun_t fun(Funtion);
                fun(sock, cur->second->_inbuffer, ptr);
                break;
            }
            else if (errno == EINTR)
            {
                std::cout << "被中断，请再试一次" << std::endl;
                continue;
            }
            else
            {
                std::cout << "recv fail:" << strerror(errno) << std::endl;
                break;
            }
        }
    }
}
void Write(int sock, std::unordered_map<int, IO *> &ptr)
{
    auto cur = ptr.find(sock);
    assert(cur != ptr.end());
    while (true)
    {
        ssize_t s = send(sock, cur->second->_outbuffer.c_str(), cur->second->_outbuffer.size(), 0);
        if (s > 0)
        {
            std::cout << "send success" << std::endl;
            cur->second->_outbuffer.erase(0, s);
            if (cur->second->_outbuffer.empty())
                break;
        }
        else
        {
            if (errno == EWOULDBLOCK || errno == EAGAIN)
            {
                std::cout << "没空间" << std::endl;
                break;
            }
            else if (errno == EINTR)
            {
                std::cout << "被中断" << std::endl;
                continue;
            }
            else
            {
                std::cout << "Write fail:" << strerror(errno) << std::endl;
                break;
            }
        }
    }
}
void handlevent(epoll_event *event, int num, int sock, std::unordered_map<int, IO *> &ptr)
{
    for (size_t i = 0; i < num; i++)
    {
        // 读事件就绪
        if (((ptr.find(event[i].data.fd) != ptr.end())) && (event[i].events & EPOLLIN))
        {
            if (event[i].data.fd == sock)
                Accept(event[i].data.fd, ptr);
            else
                Recv(event[i].data.fd, ptr);
        }
        //     // 写事件就绪
        if (((ptr.find(event[i].data.fd) != ptr.end())) && (event[i].events & EPOLLOUT))
        {
            Write(event[i].data.fd, ptr);
            auto cur = ptr.find(sock);
            assert(cur != ptr.end());
            cur->second->esp->Change(sock, false);
        }
    }
}